<template>
  <div ref="boxRef" class="full">
    <div ref="operateRef">
      <Search v-if="searches.length > 0" ref="searchRef" :action="action" class="pb2" />
      <Toolbar :actions="toolbarActions" />
      <Panel class="mt2" />
      <Stat ref="statRef" :stats="statSchema" class="mt2" />
      <Order ref="orderRef" class="mt2" />
    </div>
    <div>
      <el-table ref="tableRef" :data="dataList" highlight-current-row
        :show-summary="showSummary" :summary-method="summaries"
        :height="tableHeight" row-key="id"
        @row-click="onRowClick"
        @row-dblclick="onRowDblclick"
        @select="onSelect"
        @select-all="onSelectAll"
      >
        <el-table-column v-if="multiple" type="selection" width="55" />
        <el-table-column v-if="index" label="序号" type="index" width="80" />
        <template v-for="column in unit.columns" :key="column.name">
          <el-table-column v-if="!column.hidden" :label="column.label" :prop="column.name">
            <template v-if="hasHeader(column)" #header>
              <ColumnHead :unit="unit" :column="column" />
            </template>
            <template #="{ row }">
              <component :key="`${column.name}-${row.id}`" :column="column"
                :is="getElement(column.type, 'read', action.elements?.[column.name]?.element)"
                :model-value="getColumnValue(row, toCamelCase(column.name))"
                v-bind="action.elements?.[column.name].elementProps || {}"
              />
            </template>
          </el-table-column>
        </template>
        <el-table-column v-if="Object.keys(rowActions).length > 0" :min-width="50">
          <template #header>
            <div class="flex justify-between items-center">
              <span>操作</span>
              <ColumnFilter />
            </div>
          </template>
          <template #default="{ row }">
            <ActionBar :actions="rowActions" :row="row" />
          </template>
        </el-table-column>
      </el-table>
      <div class="flex items-center justify-between mt3px h35px">
        <div>共{{ total }}条, 已{{ multiple ? '勾选' : '选择' }}<ElButton type="primary" link @click="showSelected">【{{ multiple ? unit.selectedRows.length : (unit.currentRow ? 1 : 0) }}】</ElButton>条</div>
        <el-pagination background :page-sizes="[10, 20, 50, 100, 200, 300]" layout="sizes, jumper, prev, pager, next" v-model:page-size="pageSize" v-model:current-page="currentPage" :total="total" />
      </div>
    </div>
  </div>
</template>
<script lang="ts" setup>
  import { ref, reactive, unref, watchEffect, provide, watch, nextTick, onMounted, computed } from 'vue'
  import { initUnit } from '@/seed-application/utils/UnitUtil'
  import { findActions } from '@/seed-application/utils/SeedUtil'
  import { ElTable, ElTableColumn, ElPagination, ElButton } from 'element-plus'
  import { useTable } from '@/hooks/web/useTable'
  import { ActionBar } from '@/components/ActionBar'
  import { getTableColumns, getSearches, getOrders } from '@/seed-application/utils/SeedUtil'
  import { TableColumn } from '@/seed-application/types'
  import { toCamelCase } from '@/utils/func'
  import { pageApi } from '@/seed-application/api'
  import { getColumnValue } from '@/seed-application/utils/ColumnUtil'
  import { getAction, getElement, unitKey } from '@/seed-application'
  import { Search, Toolbar, Stat, Order, Panel, ColumnFilter, ColumnHead } from '..'

  const props = defineProps<{
    actionName: string,
    seedName?: string,
    microName?: string,
    refFieldName?: string, // 被引用的字段名，用于作为选择列表时使用
    value?: string, // 初始值, 用于作为选择列表时使用
    multiple?: boolean,
    index?: boolean,
    toolbar?:string,
    row?:string
  }>()
  const emits = defineEmits(['current-change', 'selection-change'])
  
  const boxRef = ref()
  const operateRef = ref()
  const tableRef = ref()
  const tableHeight = ref(0)
  onMounted(() => {
    nextTick(() => {
      new ResizeObserver(entries => {
        if(boxRef.value) tableHeight.value = boxRef.value.clientHeight - entries[0].contentRect.height - 38
      }).observe(operateRef.value);
    })
  })

  const action = getAction(props.actionName, props.seedName, props.microName)
  if(!action) throw Error(`【${props.actionName}】不存在`)
  const seed = action?.seed
  const statSchema = action.stats || seed.stats

  const { dataList, stats, total, currentPage, pageSize, refresh } = useTable(async () => {
    const params = {
      pageNumber: unref(currentPage),
      pageSize: unref(pageSize)
    }
    if(unit.keyword) params['keyword'] = unit.keyword
    for(const key in unit.searchData) {
      const value = unit.searchData[key]
      if(value) params[key] = value
    }
    for(const key in unit.orderData) {
      const value = unit.orderData[key]
      if(value) params[key] = value
    }
    
    const { page, stats } = await pageApi(action, params)

    return {
      list: page.records,
      total: page.totalRow,
      stats
    }
  }, boxRef)

  const searchRef = ref()
  const statRef = ref()
  const orderRef = ref()
  const unit = initUnit(reactive({ refresh, searchRef, statRef, orderRef }))
  provide(unitKey, unit)

  const toolbarActions = findActions(seed, props.toolbar || `!${action.name}`)
  const rowActions = findActions(seed, props.row)

  const index = ref(props.index)
  unit.columns = reactive(getTableColumns(action))
  const searches = getSearches(action)
  const orders = getOrders(action)
  const hasHeader = (column: TableColumn) => orders.includes(column.name)

  let manual = false // 是否已手动操作
  function onRowClick(row: Record<string, any>) {
    manual = true
    if(unit.currentRow) {
      if(unit.currentRow.id !== row.id) {
        unit.currentRow = row
        emits('current-change', row)
      }
    } else {
      unit.currentRow = row
      emits('current-change', row)
    }
  }

  function onRowDblclick() {
    manual = true
    tableRef.value.setCurrentRow()
    unit.currentRow = void 0
    emits('current-change', void 0)
  }

  function onSelect(selection, row) {
    manual = true
    const index = unit.selectedRows.findIndex(e => e.id === row.id);
    const checked = selection.find(e => e === row)
    if(checked) {
      if(index === -1) {
        unit.selectedRows.push(row)
        emits('selection-change', unit.selectedRows)
      }
    } else {
      if (index !== -1) {
        unit.selectedRows.splice(index, 1)
        emits('selection-change', unit.selectedRows)
      }
    }
  }

  function onSelectAll(selection) {
    manual = true
    const checked = selection.length > 0
    const length = unit.selectedRows.length
    for(const row of dataList.value) {
      const index = unit.selectedRows.findIndex(e => e.id === row.id);
      if(checked) {
        if(index === -1) unit.selectedRows.push(row)
      } else {
        if(index !== -1) unit.selectedRows.splice(index, 1)
      }
    }

    if(length !== unit.selectedRows.length) emits('selection-change', unit.selectedRows)
  }

  function showSelected() {
    console.log('selected', props.multiple ? unit.selectedRows : unit.currentRow)
  }

  function setSelected() {
    const refFieldName = props.refFieldName
    const value = props.value
    if(value && refFieldName && !manual) {
      if(props.multiple) {
        const values = value.split(',')
        for(const row of dataList.value) {
          if(values.includes(row[refFieldName])) {
            const index = unit.selectedRows.findIndex(e => e.id === row.id);
            if(index === -1) unit.selectedRows.push(row)
          }
        }
      } else {
        unit.currentRow = dataList.value.find(e => e[refFieldName] == value)
      }
    }

    if(props.multiple) {
      const selectedIds = unit.selectedRows.map(e => e.id)
      for(const row of dataList.value) {
        if(selectedIds.includes(row.id)) tableRef.value.toggleRowSelection(row, true)
      }
    } else {
      if(unit.currentRow) {
        for(const row of dataList.value) {
          if(unit.currentRow.id == row.id) tableRef.value.setCurrentRow(row)
        }
      }
    }
  }

  const showSummary = computed(() => {
    const declares = unit.columns.map(e => e.name)
    for(const statName in statSchema) {
      const stat = statSchema[statName]
      if(declares.includes(stat.declare)) return true
    }

    return false
  })

  const summaries = ({ columns }) => {
    const sums: string[] = []

    for(const i in columns) {
      const column = columns[i]
      const declare = column.property
      if(!declare) continue

      const values = getStatValues(declare)      
      sums[i] = values.length > 0 ? values.map(e => `${e.label}: ${e.value}`) : ''
    }

    return sums
  }

  function getStatValues(declare: string) {
    const ret = []
    for(const statName in statSchema) {
      const stat = statSchema[statName]
      if(stat.declare === declare) {
        const value = stats.value[statName]
        if(value !== void 0 && value !== '') ret.push({label: stat.label, value})
      }
    }

    return ret
  }

  watchEffect(() => unit.statData = stats.value)

  // 处理表格数据选中
  watch([() => props.value, () => dataList.value], () => nextTick(setSelected))

  defineExpose({ refresh })
</script>
<style scoped>
  /* 修改高亮当前行颜色 */
  :deep(.el-table tbody tr:hover>td) {
    background: #D4D7DE !important;
  }

  :deep(.el-table tbody tr.current-row>td) {
    background: #09e0f0 !important;
    color: #FFF;
  }

  .box {
    display: grid;
    grid-template-columns: repeat(10, 1fr);
    gap: 10px 2px;

    div {
      grid-auto-flow: row dense;
    }
  }
</style>
